package org.third.integration.ldap;

import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import sun.security.util.HostnameChecker;

public class LdapSslSocketDelegate extends javax.net.ssl.SSLSocket {
    private javax.net.ssl.SSLSocket sslSocket;

    public LdapSslSocketDelegate(SSLSocket sslSocket) {        
        this.sslSocket = sslSocket;
        validateSession(sslSocket);
    }

    /**
     * @return
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return this.sslSocket.hashCode();
    }

    /**
     * @param obj
     * @return
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
        return this.sslSocket.equals(obj);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
     */
    public String[] getSupportedCipherSuites() {
        return this.sslSocket.getSupportedCipherSuites();
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
     */
    public String[] getEnabledCipherSuites() {
        return this.sslSocket.getEnabledCipherSuites();
    }

    /**
     * @param suites
     * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
     */
    public void setEnabledCipherSuites(String[] suites) {
        this.sslSocket.setEnabledCipherSuites(suites);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
     */
    public String[] getSupportedProtocols() {
        return this.sslSocket.getSupportedProtocols();
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
     */
    public String[] getEnabledProtocols() {
        return this.sslSocket.getEnabledProtocols();
    }

    /**
     * @param protocols
     * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
     */
    public void setEnabledProtocols(String[] protocols) {
        this.sslSocket.setEnabledProtocols(protocols);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getSession()
     */
    public SSLSession getSession() {
        return this.sslSocket.getSession();
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getHandshakeSession()
     */
    public SSLSession getHandshakeSession() {
        return this.sslSocket.getHandshakeSession();
    }

    /**
     * @param listener
     * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
     */
    public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
        this.sslSocket.addHandshakeCompletedListener(listener);
    }

    /**
     * @param listener
     * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
     */
    public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
        this.sslSocket.removeHandshakeCompletedListener(listener);
    }

    /**
     * @throws IOException
     * @see javax.net.ssl.SSLSocket#startHandshake()
     */
    public void startHandshake() throws IOException {
        this.sslSocket.startHandshake();
    }

    /**
     * @param mode
     * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
     */
    public void setUseClientMode(boolean mode) {
        this.sslSocket.setUseClientMode(mode);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getUseClientMode()
     */
    public boolean getUseClientMode() {
        return this.sslSocket.getUseClientMode();
    }

    /**
     * @param need
     * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
     */
    public void setNeedClientAuth(boolean need) {
        this.sslSocket.setNeedClientAuth(need);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
     */
    public boolean getNeedClientAuth() {
        return this.sslSocket.getNeedClientAuth();
    }

    /**
     * @param endpoint
     * @throws IOException
     * @see java.net.Socket#connect(java.net.SocketAddress)
     */
    public void connect(SocketAddress endpoint) throws IOException {
        this.sslSocket.connect(endpoint);
        validateSession(sslSocket);
    }

    private static final void validateSession(javax.net.ssl.SSLSocket sslSocket) {
        SSLSession sslSession = sslSocket.getSession();
        String hostname = "";
        HostnameChecker checker = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS);
        try {
//            checker.match(hostname, (X509Certificate) sslSession.getPeerCertificates()[0]);
        }catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param want
     * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
     */
    public void setWantClientAuth(boolean want) {
        this.sslSocket.setWantClientAuth(want);
    }

    /**
     * @param endpoint
     * @param timeout
     * @throws IOException
     * @see java.net.Socket#connect(java.net.SocketAddress, int)
     */
    public void connect(SocketAddress endpoint, int timeout) throws IOException {
        this.sslSocket.connect(endpoint, timeout);
        validateSession(sslSocket);

    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getWantClientAuth()
     */
    public boolean getWantClientAuth() {
        return this.sslSocket.getWantClientAuth();
    }

    /**
     * @param flag
     * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
     */
    public void setEnableSessionCreation(boolean flag) {
        this.sslSocket.setEnableSessionCreation(flag);
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
     */
    public boolean getEnableSessionCreation() {
        return this.sslSocket.getEnableSessionCreation();
    }

    /**
     * @return
     * @see javax.net.ssl.SSLSocket#getSSLParameters()
     */
    public SSLParameters getSSLParameters() {
        return this.sslSocket.getSSLParameters();
    }

    /**
     * @param bindpoint
     * @throws IOException
     * @see java.net.Socket#bind(java.net.SocketAddress)
     */
    public void bind(SocketAddress bindpoint) throws IOException {
        this.sslSocket.bind(bindpoint);
    }

    /**
     * @param params
     * @see javax.net.ssl.SSLSocket#setSSLParameters(javax.net.ssl.SSLParameters)
     */
    public void setSSLParameters(SSLParameters params) {
        this.sslSocket.setSSLParameters(params);
    }

    /**
     * @return
     * @see java.net.Socket#getInetAddress()
     */
    public InetAddress getInetAddress() {
        return this.sslSocket.getInetAddress();
    }

    /**
     * @return
     * @see java.net.Socket#getLocalAddress()
     */
    public InetAddress getLocalAddress() {
        return this.sslSocket.getLocalAddress();
    }

    /**
     * @return
     * @see java.net.Socket#getPort()
     */
    public int getPort() {
        return this.sslSocket.getPort();
    }

    /**
     * @return
     * @see java.net.Socket#getLocalPort()
     */
    public int getLocalPort() {
        return this.sslSocket.getLocalPort();
    }

    /**
     * @return
     * @see java.net.Socket#getRemoteSocketAddress()
     */
    public SocketAddress getRemoteSocketAddress() {
        return this.sslSocket.getRemoteSocketAddress();
    }

    /**
     * @return
     * @see java.net.Socket#getLocalSocketAddress()
     */
    public SocketAddress getLocalSocketAddress() {
        return this.sslSocket.getLocalSocketAddress();
    }

    /**
     * @return
     * @see java.net.Socket#getChannel()
     */
    public SocketChannel getChannel() {
        SocketChannel ins= this.sslSocket.getChannel();
        validateSession(sslSocket);        
        return ins;
    }

    /**
     * @return
     * @throws IOException
     * @see java.net.Socket#getInputStream()
     */
    public InputStream getInputStream() throws IOException {
        InputStream ins= this.sslSocket.getInputStream();
        validateSession(sslSocket);        
        return ins;
    }

    /**
     * @return
     * @throws IOException
     * @see java.net.Socket#getOutputStream()
     */
    public OutputStream getOutputStream() throws IOException {
        return this.sslSocket.getOutputStream();
    }

    /**
     * @param on
     * @throws SocketException
     * @see java.net.Socket#setTcpNoDelay(boolean)
     */
    public void setTcpNoDelay(boolean on) throws SocketException {
        this.sslSocket.setTcpNoDelay(on);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getTcpNoDelay()
     */
    public boolean getTcpNoDelay() throws SocketException {
        return this.sslSocket.getTcpNoDelay();
    }

    /**
     * @param on
     * @param linger
     * @throws SocketException
     * @see java.net.Socket#setSoLinger(boolean, int)
     */
    public void setSoLinger(boolean on, int linger) throws SocketException {
        this.sslSocket.setSoLinger(on, linger);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getSoLinger()
     */
    public int getSoLinger() throws SocketException {
        return this.sslSocket.getSoLinger();
    }

    /**
     * @param data
     * @throws IOException
     * @see java.net.Socket#sendUrgentData(int)
     */
    public void sendUrgentData(int data) throws IOException {
        this.sslSocket.sendUrgentData(data);
    }

    /**
     * @param on
     * @throws SocketException
     * @see java.net.Socket#setOOBInline(boolean)
     */
    public void setOOBInline(boolean on) throws SocketException {
        this.sslSocket.setOOBInline(on);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getOOBInline()
     */
    public boolean getOOBInline() throws SocketException {
        return this.sslSocket.getOOBInline();
    }

    /**
     * @param timeout
     * @throws SocketException
     * @see java.net.Socket#setSoTimeout(int)
     */
    public void setSoTimeout(int timeout) throws SocketException {
        this.sslSocket.setSoTimeout(timeout);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getSoTimeout()
     */
    public int getSoTimeout() throws SocketException {
        return this.sslSocket.getSoTimeout();
    }

    /**
     * @param size
     * @throws SocketException
     * @see java.net.Socket#setSendBufferSize(int)
     */
    public void setSendBufferSize(int size) throws SocketException {
        this.sslSocket.setSendBufferSize(size);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getSendBufferSize()
     */
    public int getSendBufferSize() throws SocketException {
        return this.sslSocket.getSendBufferSize();
    }

    /**
     * @param size
     * @throws SocketException
     * @see java.net.Socket#setReceiveBufferSize(int)
     */
    public void setReceiveBufferSize(int size) throws SocketException {
        this.sslSocket.setReceiveBufferSize(size);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getReceiveBufferSize()
     */
    public int getReceiveBufferSize() throws SocketException {
        return this.sslSocket.getReceiveBufferSize();
    }

    /**
     * @param on
     * @throws SocketException
     * @see java.net.Socket#setKeepAlive(boolean)
     */
    public void setKeepAlive(boolean on) throws SocketException {
        this.sslSocket.setKeepAlive(on);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getKeepAlive()
     */
    public boolean getKeepAlive() throws SocketException {
        return this.sslSocket.getKeepAlive();
    }

    /**
     * @param tc
     * @throws SocketException
     * @see java.net.Socket#setTrafficClass(int)
     */
    public void setTrafficClass(int tc) throws SocketException {
        this.sslSocket.setTrafficClass(tc);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getTrafficClass()
     */
    public int getTrafficClass() throws SocketException {
        return this.sslSocket.getTrafficClass();
    }

    /**
     * @param on
     * @throws SocketException
     * @see java.net.Socket#setReuseAddress(boolean)
     */
    public void setReuseAddress(boolean on) throws SocketException {
        this.sslSocket.setReuseAddress(on);
    }

    /**
     * @return
     * @throws SocketException
     * @see java.net.Socket#getReuseAddress()
     */
    public boolean getReuseAddress() throws SocketException {
        return this.sslSocket.getReuseAddress();
    }

    /**
     * @throws IOException
     * @see java.net.Socket#close()
     */
    public void close() throws IOException {
        this.sslSocket.close();
    }

    /**
     * @throws IOException
     * @see java.net.Socket#shutdownInput()
     */
    public void shutdownInput() throws IOException {
        this.sslSocket.shutdownInput();
    }

    /**
     * @throws IOException
     * @see java.net.Socket#shutdownOutput()
     */
    public void shutdownOutput() throws IOException {
        this.sslSocket.shutdownOutput();
    }

    /**
     * @return
     * @see java.net.Socket#toString()
     */
    public String toString() {
        return this.sslSocket.toString();
    }

    /**
     * @return
     * @see java.net.Socket#isConnected()
     */
    public boolean isConnected() {
        return this.sslSocket.isConnected();
    }

    /**
     * @return
     * @see java.net.Socket#isBound()
     */
    public boolean isBound() {
        return this.sslSocket.isBound();
    }

    /**
     * @return
     * @see java.net.Socket#isClosed()
     */
    public boolean isClosed() {
        return this.sslSocket.isClosed();
    }

    /**
     * @return
     * @see java.net.Socket#isInputShutdown()
     */
    public boolean isInputShutdown() {
        return this.sslSocket.isInputShutdown();
    }

    /**
     * @return
     * @see java.net.Socket#isOutputShutdown()
     */
    public boolean isOutputShutdown() {
        return this.sslSocket.isOutputShutdown();
    }

    /**
     * @param connectionTime
     * @param latency
     * @param bandwidth
     * @see java.net.Socket#setPerformancePreferences(int, int, int)
     */
    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
        this.sslSocket.setPerformancePreferences(connectionTime, latency, bandwidth);
    }

}
